home *** CD-ROM | disk | FTP | other *** search
/ Singles Flirt Up Your Life! (German) / Singles Flirt Up Your Life.iso / data1.cab / Script / initGame.lua < prev    next >
Text File  |  2004-01-29  |  71KB  |  2,491 lines

  1. -- globals
  2. include("globals")
  3.  
  4. -- disable print if wstats is not defined mode
  5. if (not isDefined("WSTATS")) then
  6.     print("disabling lua print");
  7.     print = function() end
  8. end
  9.  
  10. -- high level convenience scription functions
  11.  
  12. -- this: global
  13. -- object: StandardGO
  14. -- checks if this item is on a table, if there is a chair on the closest
  15. -- action point and returns the chair game object, otherwise it returns nil
  16.  
  17. function getChairForItemOnTable(object, character)
  18.  
  19.     local goParent = object.getGOParent();
  20. --    local currentCharacter = object.getGameObjectServer().getCurrentCharacter();
  21.     
  22.     if (goParent) then
  23.         if (goParent.hasBehavior("table")) then
  24.             -- check if chair is on action point
  25. --            local chairActionPoint = object.getClosestActionPoint(currentCharacter);
  26.             local chairActionPoint = object.getActionPoint("chair");
  27.             if (chairActionPoint) then
  28.                 local chair = object.getGameObjectOnActionPoint(chairActionPoint.getName());
  29.                 if (chair) then
  30.                     if (chair.hasBehavior("chair")) then
  31.                         --orientation must be correct
  32.                         if (chair.hasActionPointOrientation(chairActionPoint)) then
  33.                             return chair;
  34.                         else
  35.                             print("wrong orientation");
  36.                         end
  37.                     else
  38.                         print("this is not a chair");
  39.                     end
  40.                 else
  41.                     print("must sit on something");
  42.                 end
  43.             else
  44.                 print("the current object has no action point");
  45.             end
  46.         else
  47.             print("the computer must stand on a table");
  48.         end
  49.     else
  50.         print("the computer must not stand on the ground");
  51.     end    
  52.     
  53.     return nil;
  54. end
  55.  
  56.  
  57.  
  58. function enumCompare(enum1, enum2)
  59.     if (tonumber(enum1) == tonumber(enum2)) then
  60.         return true;
  61.     else
  62.         return false;
  63.     end
  64. end
  65.  
  66.  
  67. -- this: walkStateObject
  68. -- chooses an action and does the action, if one was chosen
  69. function doSomething()
  70.  
  71.     local character = getParent();
  72.     print("doSomething "  .. character.getCharacterName() .. "--getActivityQueueCount:" .. character.getActivityQueueCount());
  73.     
  74.     if (character.getActivityQueueCount() == 0) then
  75.         
  76.         -- AI
  77.         local ai = character.getGameObjectServer().autonomousCharacters();
  78.         
  79.         if (ai) then
  80.                 
  81.             if (not urgentOutfitChange(character)) then
  82.             
  83.                 print("doSomething chooseCommand");
  84.                 local chosenObjectCommand = character.chooseCommand();
  85.                 if (chosenObjectCommand) then
  86.                     print("doSomething queue chosenObjectCommand");
  87.                     character.queueCommand(chosenObjectCommand, true);
  88.                 else
  89.                     --print("doSomething goAway");
  90.                     if (character.isSwimming()) then
  91.                         sendMsg("goAway", character.walkSO);
  92.                     else
  93.                         makeConditionPose();
  94.                     end
  95.                 end
  96.             end
  97.                     
  98.         else
  99.             print("doSomething ai disabled");
  100.             makeConditionPose();
  101.         end
  102.         
  103.         
  104.     end
  105. end
  106.  
  107. function urgentOutfitChange(character)
  108.  
  109.     if (not character.getGameObjectServer().automaticActions()) then
  110.         return false;
  111.     end
  112.     
  113.     if not checkShyness(character) then
  114.         return false;
  115.     end
  116.     
  117.     local kommoden = character.getPrivateObjectsWithBehavior("kommode");
  118.     for k = 1, getn(kommoden) do
  119.         local kommode = kommoden[k];
  120.         if (not kommode.isBroken()) then
  121.             local outfit = character.getOutfitDescription(ARCHTYPE);
  122.             character.queueCommand(outfit.getName(), "outfit", kommode, tostring(outfit.getID()));
  123.             return true;
  124.         end    
  125.     end
  126.     
  127.     return false;
  128. end
  129.  
  130. -- this: walkStateObject
  131. --function urgentArgueCharacter(activeCharacter)
  132. --    
  133. --    local others = activeCharacter.getOtherCharacters();
  134. --    
  135. --    for index, passiveCharacter in others do
  136. --        if (checkInjustice(activeCharacter, passiveCharacter) and not passiveCharacter.isBusy()) then
  137. --            activeCharacter.queueCommand("pm_talkArgue", "talk", passiveCharacter, "Argue");
  138. --            return true;
  139. --        end
  140. --    end
  141. --    
  142. --    return false;
  143. --end
  144.  
  145. function checkInjustice(activeCharacter)
  146.  
  147.     local justiceValue = activeCharacter.getCondition(NEED_JUSTICE);
  148.     local tolerance = activeCharacter.getJusticeTolerance();
  149.     local passiveCharacter = getOtherCharacter(activeCharacter);
  150.     
  151.     if (justiceValue < activeCharacter.getJusticeTolerance()) and (not passiveCharacter.isBusy()) then
  152.         activeCharacter.queueCommand("pm_talkArgue", "talk", passiveCharacter, "Argue");
  153.         return true;
  154.     end
  155.     
  156.     if (justiceValue < lerp(tolerance, 1.0, tonumber(readConfig("Game", "justiceWarningLevel", "0.3")))) then
  157.         activeCharacter.setEmoticon(EMOTICON_JUSTICE, EMOTICON_DELAY);
  158.         return true;
  159.     end
  160.     
  161.     return false;
  162.     
  163. end
  164.  
  165.  
  166. -- this: walkStateObject
  167. function makeConditionPose()
  168.  
  169.     local character = getParent();
  170.     
  171.     if (not character.getGameObjectServer().automaticActions()) then
  172.         return
  173.     end
  174.     
  175.     if checkShyness(character) then
  176.         return
  177.     end
  178.     
  179. --    if (urgentArgueCharacter(character)) then
  180. --        return
  181. --    end
  182.  
  183.     if checkInjustice(character) then
  184.         return
  185.     end
  186.     
  187.     local now = character.getGameObjectServer().getGameTime();
  188.     local nextPoseTime = character.retrieveData("nextPoseTime", 0);
  189.     --print("makeConditionPose: now " .. now .. " nextPoseTime " .. nextPoseTime .. " for " .. character.getCharacterName());
  190.     
  191.     if (now < nextPoseTime) then
  192.         --print("makeConditionPose: return now < nextPoseTime");
  193.         return
  194.     end
  195.     
  196.     character.setEmoticon("");
  197.     
  198.     nextPoseTime = now + random(CONDITION_POSE_PAUSE, CONDITION_POSE_PAUSE * 2);
  199.     
  200.     if (random() > CONDITION_POSE_PROB) then
  201.         --print("makeConditionPose: return CONDITION_POSE_PROB");
  202.         character.storeData("nextPoseTime", nextPoseTime);
  203.         return
  204.     end
  205.     
  206.     -- interaction poses
  207.     local partner = getOtherCharacter(character);
  208.             
  209.     local needs = character.getNeedsSorted();
  210.     local worstNeed = needs[1];
  211.     --print("  worstNeed:", worstNeed);
  212.     
  213.     --for testing
  214.     if (enumCompare(worstNeed, NEED_APARTMENT)) then worstNeed = needs[2]; end;
  215.     
  216.     local worstNeedValue = character.getCondition(worstNeed);
  217.     --print("  worstNeedValue:", worstNeedValue);
  218.     
  219.     
  220.     if (partner) then
  221.         local distance = character.getDistanceToGameObject(partner);
  222.         
  223.         -- smell the other character
  224.         if (distance < 2.0) then
  225.             local partnersHygiene = partner.getCondition(NEED_HYGIENE);
  226.             local partnersState = partner.walkSO.getStateMachine().getName();
  227.             if ((partnersHygiene < 0.2) or (partnersState == "toiletChar")) then
  228.                 partner.sendMsg("emoYouSmell", character.walkSO);
  229.                 character.setEmoticon(EMOTICON_SMELL, EMOTICON_DELAY);
  230.                 character.storeData("nextPoseTime", nextPoseTime);
  231.                 return
  232.             end
  233.         end
  234.         
  235.         -- flirt
  236.         if (distance < 4.0) then
  237.             if (enumCompare(worstNeed, NEED_LIBIDO) and (worstNeedValue < 0.2)) then
  238.                 partner.sendMsg("emoFlirt", character.walkSO);
  239.                 character.setEmoticon(EMOTICON_EROTIC, EMOTICON_DELAY);
  240.                 character.storeData("nextPoseTime", nextPoseTime);
  241.                 return
  242.             end
  243.         end
  244.         
  245.     end
  246.     
  247.     
  248.     
  249.     
  250.     if (worstNeedValue > 0.7) then
  251.         -- happy because all needs satisfied
  252.         character.setEmoticon(EMOTICON_SMILE, EMOTICON_DELAY);
  253.         sendMsg("emoHappy", character.walkSO);
  254.         character.storeData("nextPoseTime", nextPoseTime);
  255.         return
  256.     end
  257.     
  258.  
  259.     if (worstNeedValue > 0.2) then
  260.         -- nothing really critical
  261.         return
  262.     end
  263.     
  264.     
  265.     -- no fun
  266.     if (enumCompare(worstNeed, NEED_FUN)) then
  267.         sendMsg("emoSwing", character.walkSO);
  268.         character.setEmoticon(EMOTICON_SAD, EMOTICON_DELAY);
  269.         character.storeData("nextPoseTime", nextPoseTime);
  270.     -- no comfort
  271.     elseif (enumCompare(worstNeed, NEED_COMFORT)) then
  272.         sendMsg("emoSwing", character.walkSO);
  273.         character.setEmoticon(EMOTICON_SAD, EMOTICON_DELAY);
  274.         character.storeData("nextPoseTime", nextPoseTime);
  275.     -- bad apartment
  276.     elseif (enumCompare(worstNeed, NEED_APARTMENT)) then
  277.         sendMsg("emoThink", character.walkSO);
  278.         character.setEmoticon(EMOTICON_APARTMENT, EMOTICON_DELAY);
  279.         character.storeData("nextPoseTime", nextPoseTime);
  280.     -- no hygiene
  281.     elseif (enumCompare(worstNeed, NEED_HYGIENE)) then
  282.         sendMsg("emoHygiene", character.walkSO);
  283.         character.setEmoticon(EMOTICON_SMELL, EMOTICON_DELAY);
  284.         character.storeData("nextPoseTime", nextPoseTime);
  285.     -- hungry
  286.     elseif (enumCompare(worstNeed, NEED_HUNGER)) then
  287.         sendMsg("emoHungry", character.walkSO);
  288.         character.setEmoticon(EMOTICON_SAD, EMOTICON_DELAY);
  289.         character.storeData("nextPoseTime", nextPoseTime);
  290.     -- tired
  291.     elseif (enumCompare(worstNeed, NEED_TIREDNESS)) then
  292.         sendMsg("emoYawn", character.walkSO);
  293.         character.setEmoticon(EMOTICON_SLEEPY, EMOTICON_DELAY);
  294.         character.storeData("nextPoseTime", nextPoseTime);
  295.     end
  296.     
  297.  
  298. end
  299.  
  300. -- returns true if character activeCharacter is ashamed of passiveCharacter
  301. -- in the current state
  302. function isCharacterAshamed(activeCharacter, passiveCharacter)
  303.  
  304.     if (hasOutfit(activeCharacter, UNDERWEAR) or hasOutfit(activeCharacter, TOWEL)) then
  305.         local activity = activeCharacter.createActivity("showInUnderwear", passiveCharacter)
  306.         return not enumCompare(activity.getActivityResult(), POSSIBLE)
  307.     elseif hasOutfit(activeCharacter, NOTHING) then
  308.         local activity = activeCharacter.createActivity("showNaked", passiveCharacter)
  309.         return not enumCompare(activity.getActivityResult(), POSSIBLE)
  310.     end
  311.     
  312.     return false;
  313. end
  314.     
  315. function checkShyness(character)
  316.  
  317.     if (hasOutfit(character, UNDERWEAR) or hasOutfit(character, TOWEL)) then
  318.         local other, result = getDisturbingChar(character, "showInUnderwear")
  319.         if (other) then
  320.             --character.setEmoticon(EMOTICON_SHY, EMOTICON_DELAY);
  321.             other.sendMsg("emoShameChar", character.walkSO);        
  322.             return true;    
  323.         end;
  324.     elseif hasOutfit(character, NOTHING) then
  325.         local other, result = getDisturbingChar(character, "showNaked")
  326.         if (other) then
  327.             --character.setEmoticon(EMOTICON_SHY, EMOTICON_DELAY);
  328.             other.sendMsg("emoShameNackedChar", character.walkSO);        
  329.             return true;    
  330.         end;
  331.     end;
  332.  
  333.     return false;    
  334.  
  335.  
  336. --    
  337. --    local others = character.getCharactersInRoom();
  338. --            
  339. --    for c = 1, getn(others) do
  340. --        local other = others[c];
  341. --        --print("checkShyness other found");
  342. --        if (not activityPossible(character, "showInUnderwear", other)) then
  343. --            --print("checkShyness sendMsg emoShame");
  344. --            character.setEmoticon(EMOTICON_SHY, EMOTICON_DELAY);
  345. --            other.sendMsg("emoShameChar", character.walkSO);        
  346. --            return true;    
  347. --        end;
  348. --    end;
  349. --    
  350. --    return false;
  351.     
  352. end
  353.  
  354. -- looks for other character in same room on wich the given activity is not possible
  355. function getDisturbingChar(character, activity)
  356.  
  357.     local others = character.getCharactersInRoom();
  358.             
  359.     for c = 1, getn(others) do
  360.         local other = others[c];
  361.         
  362.         local watchedActionPoint = other.getActionPoint("kiss");
  363.         local watchingActionPoint = character.getActionPoint("kiss");
  364.         
  365.         -- check line of sigth
  366.         local gameObjectServer = character.getGameObjectServer();
  367.         --local blockingObject = gameObjectServer.getGameObjectBetween(watchingActionPoint, watchedActionPoint, 1.5, 1.5);
  368.         local blockingObject = character.getGameObjectBetween(other, "center", "center", 1.7, 1.7);
  369.         if (not blockingObject) then
  370.             if (not character) then print("getDisturbingChar character == nil"); end;                    
  371.             local possible, result = activityPossible(character, activity, other);
  372.             if (not possible) then
  373.                 return other, result;    
  374.             end;
  375.         else
  376.             print("getDisturbingChar :: Sight from " .. character.getType() .. " blocked by " .. blockingObject.getType());
  377.             return nil;
  378.         end
  379.     end;
  380.     
  381.     return nil;    
  382. end
  383.  
  384.  
  385. function getActionPointsInSight(fromObject, fromActionPointName, fromHeight, toObject, toActionPointNames, toHeight, ignoredObject)
  386.  
  387.     local result = {};
  388.     
  389.     for p = 1, getn(toActionPointNames) do
  390.         local toActionPointName = toActionPointNames[p];
  391.         local blockingObject = fromObject.getGameObjectBetween(toObject, fromActionPointName, toActionPointName, fromHeight, toHeight, true);
  392.         
  393.         if ((not blockingObject) or (blockingObject == ignoredObject)) then
  394.             print("getActionPointsInSight toActionPointName:" .. toActionPointName .. " OK");
  395.             tinsert(result, toActionPointName);
  396.         else
  397.             print("getActionPointsInSight toActionPointName:" .. toActionPointName .. " blocked by:" .. blockingObject.getType());
  398.         end
  399.     end
  400.     
  401.     --print("getActionPointsInSight input:  " .. tostring(toActionPointNames))
  402.     --print("getActionPointsInSight output: " .. tostring(result))
  403.     
  404.     return result;
  405. end
  406.  
  407.  
  408. function getOtherCharacter(thisChar)
  409.     if (thisChar) then
  410.         local others = thisChar.getOtherCharacters();
  411.         return others[1];
  412.     else
  413.         return nil
  414.     end
  415. end
  416.  
  417.  
  418. -- this: walkStateObject
  419. function actionComplete()
  420.     if (this.actionComplete()) then
  421.         doSomething();
  422.     end
  423. end
  424.  
  425. -- this: walkStateObject
  426. -- this is called when the caracter is sleeping    
  427. -- returns true if sleeping shall be canceled
  428. function testCancelSleeping()
  429.     local goOnSleeping = true 
  430.     
  431.     local character = getParent()
  432.     
  433.     -- local currentDate = GameDate.createGameDate(character.getGameObjectServer().getGameTime());
  434.     local currentDate = character.getGameObjectServer().getGameDate()
  435.     local workPrepareTime = character.retrieveData("workPrepareTime", 2);
  436.     local getUpTime = character.getWorkBeginTime().getHoursF() - workPrepareTime;
  437.     
  438. --    print("testCancelSleeping: " .. character.getCharacterName() .. "-------------------------");
  439. --    print("workPrepareTime: " .. workPrepareTime);
  440. --    print("getUpTime: " .. getUpTime);
  441. --    print("character.getCondition(NEED_TIREDNESS): " .. character.getCondition(NEED_TIREDNESS));
  442. --    print("currentDate.isWorkingDay(): " .. tostring(currentDate.isWorkingDay()));
  443. --    print("currentDate.getHoursF(): " .. currentDate.getHoursF());
  444.             
  445.     -- get up if it is time to get up
  446.     -- characters must be at least "minGetUpTiredness" rested
  447.     local minGetUpTiredness = tonumber(readConfig("Game", "minGetUpTiredness", "0.8"));
  448.     
  449.     if (character.getCondition(NEED_TIREDNESS) > minGetUpTiredness) then
  450.         -- check if this is working day
  451.         if (currentDate.isWorkingDay()) then
  452.             local sleepActivity = character.getCurrentActivity();
  453.             if (currentDate.getHoursF() > getUpTime) then
  454.                 if (sleepActivity) then
  455.                     -- local sleepStartDate = GameDate.createGameDate(sleepActivity.getStartTime());
  456.                     local sleepStartDate = character.getGameObjectServer().createGameDate(sleepActivity.getStartTime());
  457. --                    print("sleepStartDate.getDays(): " .. sleepStartDate.getDays());
  458. --                    print("currentDate.getDays(): " .. currentDate.getDays());
  459. --                    print("sleepStartDate.getHoursF(): " .. sleepStartDate.getHoursF());
  460.                     if ((sleepStartDate.getDays() < currentDate.getDays()) or 
  461.                         (sleepStartDate.getHoursF() < getUpTime)) then
  462.                         -- time to get up            
  463.                         goOnSleeping = false
  464.                     end
  465.                 end
  466.             end
  467.         end
  468.     end
  469.     
  470. --    -- get up if normal sleep duration in milliseconds passed
  471. --    if (sleepActivity) then
  472. --        local length = getActivityLength(sleepActivity);
  473. --        local currentTime = character.getGameObjectServer().getGameTime();
  474. --        local startTime = sleepActivity.getStartTime();
  475. --        print("length: " .. length);
  476. --        print("currentTime: " .. currentTime);
  477. --        print("startTime: " .. startTime);
  478. --        if (startTime+length < currentTime) then
  479. --            print("sleep duration passed: start:" .. startTime .. " stoptime:" .. startTime+length .. "currentTime:" .. currentTime);
  480. --            goOnSleeping = false;
  481. --        end
  482. --    end
  483.     
  484.     -- get up if not tired anymore and not in the middle of the night
  485.     local currentHours = currentDate.getHoursF();
  486.     local nightStart = tonumber(readConfig("Display", "nightTime", "22"));
  487.     local nightEnd = tonumber(readConfig("Display", "morningTime", "6"));
  488.     if (character.getCondition(NEED_TIREDNESS) > 0.99)
  489.         and (currentHours > nightEnd)
  490.         and (currentHours < nightStart) then
  491.         -- not tired anymore
  492.         goOnSleeping = false
  493.     end
  494.     
  495.     if (character.hasWalkQueued(1)) then
  496.         goOnSleeping = false;
  497.     end
  498.     
  499.     return (not goOnSleeping);
  500. end
  501.  
  502. -- looks for the closest free chair by a table
  503. function getNextFreeChairByTable(character, tableObject, checkPartnerChair)
  504.  
  505.     print("getNextFreeChairByTable");
  506.  
  507.     local tables = character.getObjectsWithBehavior("table");
  508.     -- go trough tables    
  509.     for t = 1, getn(tables) do
  510.         print(" table " .. t);
  511.         local table = tables[t]; 
  512.         local actionPoints = table.getActionPoints();
  513.         -- go trough action points of table
  514.         --for a, actionPoint in actionPoints  do
  515.         for a = 1, getn(actionPoints) do
  516.             local actionPoint = actionPoints[a];
  517.             local actionPointName = actionPoint.getName();
  518.             print(" actionPoint " .. actionPointName);
  519.             if (strsub(actionPointName,1,5) == "chair") then
  520.                 local chair = table.getGameObjectOnActionPoint(actionPointName);
  521.                 if (chair) then
  522.                     if (chair.hasBehavior("chair")) then
  523.                         local chairActionPoint = character.getClosestFreeActionPoint(character, chair, {"sit1", "sit2"}, true);
  524.                         if (chairActionPoint) then
  525.                             if (chair.hasActionPointOrientation(actionPoint)) then
  526.                                 local partnerChair = getOpposedChair(table, actionPointName);
  527.                                 print("getNextFreeChairByTable: partnerChair: "..tostring(partnerChair).." checkPartnerChair "..tostring(checkPartnerChair));
  528.                                 if (partnerChair or (not checkPartnerChair)) then
  529.                                     if (tableObject) then
  530.                                         local tablePos = tableObject.tableYPosition;
  531.                                         if (not tablePos) then print("WARNING no attribute -tableYPosition- found"); tablePos = 0; end;
  532.                                         local placeOnTable = table.canObjectBeAddedToActionPoint(tableObject, actionPointName, 0, tablePos, tableHeight);
  533.                                         if (placeOnTable) then                                
  534.                                             print("getNextFreeChairByTable:  enough place for tableObject" .. tableObject.getType());
  535.                                             return table, actionPointName, chair;
  536.                                         else
  537.                                             print("getNextFreeChairByTable:  no place on table for tableObject" .. tableObject.getType());
  538.                                         end
  539.     
  540.                                     else
  541.                                         print("getNextFreeChairByTable:  no tableObject to check");
  542.                                         return table, actionPointName, chair;
  543.                                     end
  544.                                 else
  545.                                     print("getNextFreeChairByTable partnerChair not found");
  546.                                 end    
  547.     
  548.                             else
  549.                                 print("getNextFreeChairByTable: free chair has wrong orient to table");
  550.                             end                                                                            
  551.                         else
  552.                             print("   getNextFreeChairByTable: chair is blocked");                                
  553.                         end
  554.                     else
  555.                         print("getNextFreeChairByTable: object is not a chair");                                
  556.                     end
  557.                 else
  558.                     print("getNextFreeChairByTable:nothing on actionPoint " .. actionPointName);                
  559.                 end
  560.             else
  561.                 print("getNextFreeChairByTable:not a chair actionPoint " .. actionPointName);                
  562.             end
  563.         end
  564.     end
  565.             
  566.     return nil;
  567. end
  568.  
  569. function getChildByStoredData(parent, dataName, data)
  570.  
  571.     local children = parent.getGOChildren();
  572.     for c = 1, getn(children) do
  573.         local child = children[c];
  574.         local childData = child.retrieveData(dataName);
  575.         if (childData and (childData == data)) then
  576.             return child;
  577.         end
  578.     end
  579.     return nil;
  580.  
  581. end
  582.  
  583. function getChildrenWithBehavior(parent, behavior)
  584.  
  585.     local result = {};
  586.     local children = parent.getGOChildren();
  587.     for c = 1, getn(children) do
  588.         local child = children[c];
  589.         if (child.hasBehavior(behavior)) then
  590.             tinsert(result, child);
  591.         end
  592.     end
  593.     return result;
  594.  
  595. end
  596.  
  597.  
  598. -- returns an object's action point wich is opposed to the action point described by actionPointName
  599. function getOpposedActionPoint(object, actionPointName)
  600.  
  601.     local actionPoint = object.getActionPoint(actionPointName);
  602.     if (not actionPoint) then
  603.         print("getOpposedActionPoint: no actionpoint with name " , actionPointName);
  604.     end
  605.     
  606.     local actionPoints = object.getActionPoints();
  607.     
  608.     for a = 1, getn(actionPoints) do
  609.         --local point = actionPoints[a];
  610.         --local name = currentActionPoint.getName();
  611.         if (not(actionPoints[a].getName() == actionPointName)) then
  612.         
  613.             local facing1 = actionPoints[a].getFacingFraction(actionPoint);            
  614.             local facing2 = actionPoint.getFacingFraction(actionPoints[a]);
  615.             local facing = facing1 + facing2;
  616.             
  617.             if (facing > 1.9) then
  618.                 return actionPoints[a];            
  619.             end
  620.             
  621.         end
  622.     end
  623.     
  624.     print("getOpposedActionPoint: no opposed actionpoint found for " , actionPointName);
  625.     return nil;
  626. end
  627.  
  628. function getOpposedChair(table, actionPointName)
  629.  
  630.     local oppActionPoint = getOpposedActionPoint(table, actionPointName);    
  631.     if (not oppActionPoint) then
  632.         --print("getOpposedChair: no opposed actionpoint found for " , actionPointName);
  633.         return nil;
  634.     end
  635.     
  636.     local chair = table.getGameObjectOnActionPoint(oppActionPoint.getName());
  637.     if (not chair) then
  638.         --print("getOpposedChair: nothing on opposed actionpoint " , oppActionPoint.getName());
  639.         return nil;
  640.     end
  641.     
  642.     if (not chair.hasBehavior("chair")) then
  643.         --print("getOpposedChair: not a chair on opposed actionpoint " , oppActionPoint.getName());
  644.         return nil;
  645.     end
  646.     
  647.     return chair;
  648.     
  649. end
  650.  
  651. function getTableForChair(chair)
  652.  
  653.     local tables = chair.getObjectsWithBehavior("table");
  654.     -- go trough tables    
  655.     for t = 1, getn(tables) do
  656.         print(" table " .. t);
  657.         local table = tables[t]; 
  658.         local actionPoints = table.getActionPoints();
  659.         -- go trough action points of table
  660.         for a = 1, getn(actionPoints) do
  661.             local actionPoint = actionPoints[a];
  662.             local actionPointName = actionPoint.getName();
  663.             if (strfind(actionPointName, "chair") == 1) then
  664.                 print(" actionPoint " .. actionPointName);
  665.                 local go = table.getGameObjectOnActionPoint(actionPointName);
  666.                 
  667.                 if (go == chair) then
  668.                     if (chair.hasActionPointOrientation(actionPoint)) then
  669.                         print("getTableForChair: return actionPointName " .. actionPointName);
  670.                         return table, actionPointName;
  671.                     end                                                                            
  672.                 end
  673.             end
  674.         end
  675.     end
  676.     
  677.     return nil;
  678.     
  679. end
  680.  
  681. ---- this: walk state object
  682. --function goAway()
  683. --    local queueCount = getQueueCount();
  684. --    print("queueCount: " .. queueCount);
  685. --    if (queueCount < 1) then 
  686. --        sendMsg("goAway", this);
  687. --    else
  688. --        print("dont go away, somthing to do");
  689. --    end
  690. --end
  691.  
  692.  
  693. -- this: walk state object
  694. function exitAndGoAway(minDist)
  695.  
  696.         
  697.     exitStateMachine()
  698.     
  699.     local activityQueueCount = getParent().getActivityQueueCount();
  700.     if (activityQueueCount > 0) then 
  701.         print("something to do! activityQueueCount:" .. activityQueueCount);
  702.     else
  703.         print("nothing to do -> go away !!!");
  704.         if (minDist) then
  705.             sendDelayedMsgThis("goAway", 500, tostring(minDist));
  706.         else
  707.             sendDelayedMsgThis("goAway", 500);
  708.         end
  709.     end
  710.     
  711. end
  712.  
  713.  
  714. function queueNextClean(character)
  715.     
  716.     --local character = getParent();            
  717.     local activityQueueCount = character.getActivityQueueCount();    
  718.     if (activityQueueCount > 1) then 
  719.         print("queueNextClean something to do! activityQueueCount:" .. activityQueueCount);
  720.         return
  721.     end
  722.     
  723.     local tiredness = character.getCondition(NEED_TIREDNESS);
  724.     if (tiredness < 0.1) then 
  725.         print("queueNextClean too tired" .. tiredness);
  726.         return
  727.     end
  728.     
  729.     local nextDirty = getNextDirtyObject(character);
  730.     if (nextDirty) then
  731.         print("queueNextClean next:" .. nextDirty.getType());
  732.         character.queueCommand("pm_clean", "clean", nextDirty, "");
  733.     else
  734.         print("queueNextClean nothing to clean");
  735.     end 
  736.     
  737. end
  738.  
  739. function getNextDirtyObject(character)
  740.  
  741.     local cleanables = character.getObjectsWithBehavior("cleanable");
  742.     local characterRoom = character.getRoomNumber();
  743.     for c = 1, getn(cleanables) do
  744.         local cleanable = cleanables[c];
  745.         if (cleanable.getDirtiness() > 0.01) and (cleanable.getRoomNumber() == characterRoom) then
  746.             return cleanable;
  747.         end
  748.     end 
  749.     
  750.     return nil;
  751.  
  752. end
  753.  
  754. function getNextTableWithDishes(character)
  755.  
  756.     local tables = character.getObjectsWithBehavior("table");
  757.     local dishFound = false;
  758.     -- go trough tables    
  759.     for t = 1, getn(tables) do
  760.         print(" table " .. t);
  761.         local table = tables[t];
  762.         local dishes = getChildrenWithBehavior(table, "dish");
  763.         local dish = dishes[1];
  764.         
  765.         if (dish) then
  766.             dishFound = true;
  767.             --local actionPoint = character.getClosestFreeActionPoint(dish, table, {"front1", "front2"});
  768.             local actionPoint = character.getClosestFreeActionPoint(dish, table);
  769.             if (actionPoint) then
  770.                 return table, actionPoint, dishFound;
  771.             else
  772.                 print("no actionPoint");
  773.             end
  774.         else
  775.             print("no dish");
  776.         end
  777.                 
  778. --        if (getn(dishes) > 0) then
  779. --            return table;
  780. --        end
  781.          
  782.     end
  783.     return nil, nil, dishFound;
  784. end
  785.  
  786.  
  787. function getReachableObjectWithBehavior(character, behavior, actionPointNames, checkBroken)
  788.  
  789.     local objects = character.getObjectsWithBehavior(behavior);
  790.     for o = 1, getn(objects) do
  791.         local object = objects[o];
  792.         if ((not checkBroken) or (not object.isBroken())) then
  793.             local actionPoint = character.getClosestFreeActionPoint(character, object, actionPointNames, true);
  794.             if (actionPoint) then
  795.                 return object, actionPoint;
  796.             end
  797.         end
  798.     end
  799.     return nil;
  800.     
  801. end
  802.  
  803.  
  804. function getNextReadSit(character)
  805.  
  806.     return getReachableObjectWithBehavior(character, "readSeat", {"sit", "sit1", "sit2", "sit3"}, true)
  807.  
  808.  
  809. --    local seats = character.getObjectsWithBehavior("readSeat");
  810. --    print("getNextReadSit total seats" .. getn(seats));
  811. --    for s = 1, getn(seats) do
  812. --        local seat = seats[s];
  813. --        print("   getNextReadSit seat no" .. s);
  814. --        
  815. --        if (not seat.isBroken()) then
  816. --        
  817. --            print("seat " .. s .. " is " .. seats[s].getResourceName());
  818. --            local actionPoint = character.getClosestFreeActionPoint(character, seat, {"sit", "sit1", "sit2", "sit3"}, true);
  819. --            if (actionPoint) then
  820. --                return seat, actionPoint;
  821. --            end
  822. --        
  823. --        end
  824. --    end
  825. --    return nil;    
  826. end
  827.  
  828. -- looks for a seat to watch an objects "watch" actionpoint
  829. function getNextWatchSit(character, watchedObject, objectHeight, seatHeigth)
  830.     print("getNextWatchSit");
  831.     
  832.     watchedActionPoint = watchedObject.getActionPoint("watch");
  833.     if (not watchedActionPoint) then
  834.         print("watchedObject has no action point --watch--");
  835.         return nil;
  836.     end    
  837.     
  838.     local bestSeat = nil;
  839.     local bestActionPointName = "";
  840.     local bestFacing = 1;
  841.     
  842.     local maxFacing = MAX_WATCH_FACING;
  843.     local maxDistance = MAX_WATCH_DISTANCE;
  844.  
  845.     local gameObjectServer = watchedObject.getGameObjectServer();
  846.     local seats = watchedObject.getObjectsWithBehavior("watchSeat", maxDistance + 1);
  847.     
  848.     for s = 1, getn(seats) do
  849.         local seat = seats[s];
  850.         print(" seat:" .. s .. " type:" .. seat.getType());
  851.         
  852.         if (not seat.isBroken()) then
  853.             
  854.             local actionPoints = character.getFreeActionPoints(seat, {"sit", "sit1", "sit2", "sit3"});
  855.             
  856.             for a = 1, getn(actionPoints) do
  857.             
  858.                 local actionPoint = actionPoints[a];
  859.                 if (character.canReachActionPoint(actionPoint)) then
  860.             
  861.                     local facing1 = actionPoint.getFacingFraction(watchedActionPoint);
  862.                     local facing2 = watchedActionPoint.getFacingFraction(actionPoint);
  863.                     local facing = max(facing1, facing2); --facing1 + facing2;
  864.                     local distance = actionPoint.getDistance(watchedActionPoint)
  865.                                 
  866.                     print("getNextWatchSit distance:"..distance.." facing1:"..facing1.." facing2:"..facing2.." facing:"..facing.." maxFacing:"..maxFacing);
  867.                     
  868.                     if ((facing < MAX_WATCH_FACING) and (distance < MAX_WATCH_DISTANCE)) then
  869.                         if (facing < bestFacing) then
  870.                         
  871.                             -- check line of sigth
  872. --                            local blockingObject = character.getGameObjectBetween(actionPoints[a], watchedActionPoint, seatHeigth, objectHeight);
  873.                             local blockingObject = seat.getGameObjectBetween(watchedObject, actionPoint.getName(), watchedActionPoint.getName(), seatHeigth, objectHeight, true);
  874.                             if (not blockingObject) then
  875.                                 bestSeat = seat;
  876.                                 bestActionPointName = actionPoint.getName(); 
  877.                                 bestFacing = facing;
  878.                             else
  879.                                 print("Sight from action point " .. actionPoint.getName() .. " blocked by " .. blockingObject.getResourceName());
  880.                             end
  881.                         end
  882.                     end
  883.                 end            
  884.             end
  885.             
  886.         else
  887.             print("seat " .. seat.getType() .. " broken");
  888.         end
  889.         
  890.         
  891.  
  892.     end
  893.     
  894.     if (bestSeat) then
  895.         print("bestActionPoint: " .. bestActionPointName .. " bestFacing" .. bestFacing);
  896.         return bestSeat, bestSeat.getActionPoint(bestActionPointName);
  897.     else
  898.         print("no watching ActionPoint found");
  899.         return nil;
  900.     end            
  901.     
  902. end
  903.  
  904.  
  905. -- frees the hands of a character. deletes held objects. removes anims from the HandStateObject
  906. function freeHands(character)
  907.  
  908.  
  909.     local leftHeldObject = character.getLeftHeldObject();
  910.     if (leftHeldObject) then
  911.         character.detachLeftObjectHolder();
  912.         print("deleting leftHeldObject " .. leftHeldObject.getResourceName());
  913.         leftHeldObject.deleteGameObject();
  914.     end
  915.     
  916.     local rightHeldObject = character.getRightHeldObject();
  917.     if (rightHeldObject) then
  918.         character.detachRightObjectHolder();
  919.         print("deleting rightHeldObject " .. rightHeldObject.getResourceName());
  920.         rightHeldObject.deleteGameObject();
  921.     end
  922.     
  923.  
  924.     local hso = character.handSO;
  925.     if (not hso) then
  926.         print("freeHands no hand state object found");
  927.     else
  928.         hso.stopAnimation();
  929.     end
  930.     
  931.     
  932. end
  933.  
  934. -- returns true if an activity on an object can be done by the given character
  935. function activityPossible(characterGO, activityName, standardGO, data, ignoreBroken)
  936.     
  937.     -- check debug flags first
  938.     if (CharacterAI.checkFailing(CharacterAI.ALWAYS_FAIL)) then return false; end
  939.     if (CharacterAI.checkFailing(CharacterAI.NEVER_FAIL)) then return true; end
  940.     
  941.     if (not type(characterGO) == "userdata") then
  942.         print("WARNING activityPossible: characterGO not valid !!!!");
  943.         return false;
  944.     end
  945.     
  946.     -- check if character is ashamed
  947.     if (standardGO.isCharacter()) then
  948.         if (isCharacterAshamed(characterGO, standardGO)) then
  949.             return false, NO_RELATIONSHIPCONDITION;
  950.         end
  951.     end
  952.     
  953.     local activity = characterGO.createActivity(activityName, standardGO);
  954.  
  955.     local activityResult = activity.getActivityResult(ignoreBroken);
  956.     
  957.     
  958. --    -- do not make it possible to sleep in bed during day time
  959. --    if (standardGO.hasBehavior("bed") and activityName == "sleep") then
  960. --        if (enumCompare(standardGO.getGameObjectServer().getDayTime(), DAY)) then
  961. --            activityResult = UNKNOWN
  962. --        end
  963. --    end
  964.  
  965. --    print("activityPossible " .. activityName .. " activityResult " .. tostring(activityResult));    
  966.     return enumCompare(activityResult, POSSIBLE), activityResult;    
  967.     
  968. end
  969.  
  970. function getActivityLength(activity)
  971.     local scale = activity.getEffectivity();
  972.     if (scale < 0.1) then scale = 1.0 end
  973.     local length = activity.getLength();
  974.     --if (length < 1000) then length = 5000 end
  975.     
  976.     length = length / scale;
  977.     
  978.     local name = activity.getActivityName();
  979.     print("getActivityLength for " .. name ..  " l:" .. length .. " s:" .. scale);    
  980.     
  981.     return length, scale;
  982.     --return 10000, 2.0;
  983.     
  984. end
  985.  
  986.  
  987. -- shows the repair menu if this game object is broken
  988. -- this: a game object
  989. -- returns true if the menu is shown
  990. function repairMenu()
  991.     if (this.isBroken()) then
  992.         this.clearPieMenu();
  993.         local button ;
  994.         button = this.addPieMenuButton(PM_REPAIR, REPAIR_COMMAND);
  995.         button.addDescription(ACTIVITY, REPAIR);
  996.         return true;
  997.     else
  998.         return false;
  999.     end
  1000. end
  1001.  
  1002. -- this: a game object
  1003. function abortIfBroken(character)
  1004.     if (this.isBroken()) then
  1005.         print("object broken");
  1006.         instantAbort(character, EMOTICON_CANNOT, "emoThink")
  1007.         return true;
  1008.     else
  1009.         return false;
  1010.     end
  1011. end
  1012.  
  1013. function playShowerAnim(shower, suffix)
  1014.     local name = shower.getResourceName();
  1015.     print("name:" .. name .. " suffix:" .. suffix);
  1016.     if (name == "showerDesign") then
  1017.         shower.startAnimation("showerDesign" .. suffix);            
  1018.     elseif (name == "showerModern") then
  1019.         shower.startAnimation("showerModern" .. suffix);            
  1020.     elseif (name == "showerOldschool") then
  1021.         shower.startAnimation("showerOldschool" .. suffix);            
  1022.     end
  1023. end
  1024.  
  1025. function holdsObject(character, objectType)
  1026.  
  1027.     --print("objectType:" .. objectType);
  1028.     
  1029.     local rightObject = character.getRightHeldObject();
  1030.     local leftObject = character.getLeftHeldObject();
  1031.     
  1032.     if (rightObject) then
  1033.         --print("rightObjectType:" .. rightObject.getType());
  1034.     
  1035.         if (rightObject.getType() == objectType) then
  1036.             --print("RIGHT_HAND:" .. objectType);
  1037.             return true, RIGHT_HAND;
  1038.         end
  1039.     end
  1040.         
  1041.     if (leftObject) then
  1042.         --print("leftObjectType:" .. leftObject.getType());
  1043.     
  1044.         if (leftObject.getType() == objectType) then
  1045.             --print("LEFT_HAND:" .. objectType);
  1046.             return true, LEFT_HAND;
  1047.         end
  1048.     end
  1049.     
  1050.     --print("NO_HAND:" .. objectType);
  1051.     return false, nil;
  1052.     
  1053. end
  1054.  
  1055.  
  1056. function genderizeReal(character, name)
  1057.  
  1058.     local male =    (character.isMale() and not character.isTransgender()) or 
  1059.             (not character.isMale() and character.isTransgender());
  1060.             
  1061.     return name .. cond(male, "Mike", "Elaine");
  1062.     
  1063. end
  1064.  
  1065. function genderizePink(character, name)
  1066.  
  1067.     local male = character.isMale()
  1068.     local homo = character.isTransgender()
  1069.     local suffix = cond(character.isMale(), cond(homo, "Pacifica", "Mike"), cond(homo, "Tom", "Elaine"));
  1070.             
  1071.     return name .. suffix;
  1072.     
  1073. end
  1074.  
  1075. function genderize(character, name)
  1076.     if (character.isMale()) then
  1077.         return name .. "Mike";
  1078.     else
  1079.         return name .. "Elaine";
  1080.     end
  1081. end
  1082.  
  1083.  
  1084. function genderizeSpeech(character, name, active, activeDiff)
  1085.  
  1086.     local maleIsActive = (character.isMale() == active);
  1087.     local suffix1 = cond(activeDiff, cond(maleIsActive, "Mike", "Elaine"), "");
  1088.     
  1089.     local homo = character.isTransgender();
  1090.     local suffix2 = cond(character.isMale(), cond(homo, "Pacifica", "Mike"), cond(homo, "Tom", "Elaine"));
  1091.     
  1092.     local result = name .. suffix1 .. "_" .. suffix2;
  1093.     
  1094.     print("genderizeSpeech:" .. character.getCharacterName() .. " text:" .. name .. " active:" .. tostring(active));
  1095.     print(">>>maleIsActive:" .. tostring(maleIsActive) .. " homo:" .. tostring(homo));
  1096.     print(">>>return: " .. result);
  1097.  
  1098.     return result;    
  1099. end
  1100.  
  1101.  
  1102.  
  1103. function archize(character, name)
  1104.     return name .. getArchtypeSuffix(character);
  1105. end
  1106.  
  1107. function archizeRun(character, name)
  1108.  
  1109.     local archtype = character.getArchtype();
  1110.     local suffix = "Standard";
  1111.             
  1112.     if (character.isMale()) then
  1113.         if    (enumCompare(archtype, CHIEF)) then suffix = "Standard"; 
  1114.         elseif    (enumCompare(archtype, BAD_BOY)) then suffix = "Bold"; 
  1115.         elseif    (enumCompare(archtype, BEST_FRIEND)) then suffix = "Standard"; 
  1116.         elseif    (enumCompare(archtype, CHARMER)) then suffix = "Standard"; 
  1117.         elseif    (enumCompare(archtype, LOST_SOUL)) then suffix = "Bold"; 
  1118.         elseif    (enumCompare(archtype, PROFESSOR)) then suffix = "Standard"; 
  1119.         elseif    (enumCompare(archtype, SWASHBUCKLER)) then suffix = "Bold";
  1120.         elseif    (enumCompare(archtype, WARRIOR)) then suffix = "Sexy";
  1121.         else    suffix = "-Standard"; end;
  1122.     else
  1123.         if    (enumCompare(archtype, BOSS)) then suffix = "Sexy";
  1124.         elseif    (enumCompare(archtype, SEDUCTRESS)) then suffix = "Sexy"; 
  1125.         elseif    (enumCompare(archtype, SPUNKY_KID)) then suffix = "Sexy"; 
  1126.         elseif    (enumCompare(archtype, FREE_SPIRIT)) then suffix = "Aktivist"; 
  1127.         elseif    (enumCompare(archtype, INNOCENT_GIRL)) then suffix = "Sexy"; 
  1128.         elseif    (enumCompare(archtype, SCIENTIST)) then suffix = "Aktivist"; 
  1129.         elseif    (enumCompare(archtype, ACTIVIST)) then suffix = "Aktivist"; 
  1130.         elseif    (enumCompare(archtype, NURSE)) then suffix = "Sexy";
  1131.         else    suffix = "-Sexy"; end;
  1132.     end
  1133.     
  1134.     return name .. suffix;
  1135.  
  1136. end
  1137.  
  1138. function archizeWalk(character, name)
  1139.  
  1140.     local archtype = character.getArchtype();
  1141.     local male = character.isMale() and not character.isTransgender();
  1142.     return name .. cond(male, "Mike", "Elaine");
  1143.  
  1144. end
  1145.  
  1146.  
  1147. function getArchtypeSuffix(character)
  1148.  
  1149.     local archtype = character.getArchtype();
  1150.         
  1151.     if (character.isMale()) then
  1152.         if    (enumCompare(archtype, CHIEF)) then return "Chief"; 
  1153.         elseif    (enumCompare(archtype, BAD_BOY)) then return "Badboy"; 
  1154.         elseif    (enumCompare(archtype, BEST_FRIEND)) then return "Bestfriend"; 
  1155.         elseif    (enumCompare(archtype, CHARMER)) then return "Charmer"; 
  1156.         elseif    (enumCompare(archtype, LOST_SOUL)) then return "Lostsoul"; 
  1157.         elseif    (enumCompare(archtype, PROFESSOR)) then return "Professor"; 
  1158.         elseif    (enumCompare(archtype, SWASHBUCKLER)) then return "Swashbuckler";
  1159.         elseif    (enumCompare(archtype, WARRIOR)) then return "Warrior";
  1160.         else    return "Mike"; end;
  1161.     else
  1162.         if    (enumCompare(archtype, BOSS)) then return "Boss";
  1163.         elseif    (enumCompare(archtype, SEDUCTRESS)) then return "Seductress"; 
  1164.         elseif    (enumCompare(archtype, SPUNKY_KID)) then return "Spunkykid"; 
  1165.         elseif    (enumCompare(archtype, FREE_SPIRIT)) then return "Freespirit"; 
  1166.         elseif    (enumCompare(archtype, INNOCENT_GIRL)) then return "Innocentgirl"; 
  1167.         elseif    (enumCompare(archtype, SCIENTIST)) then return "Scientist"; 
  1168.         elseif    (enumCompare(archtype, ACTIVIST)) then return "Activist"; 
  1169.         elseif    (enumCompare(archtype, NURSE)) then return "Nurse";
  1170.         else    return "Elaine"; end;
  1171.     end
  1172. end
  1173.  
  1174. function findBedForInteraction(character1, character2)
  1175.  
  1176.     local beds = character1.getObjectsWithBehavior("doublebed");
  1177.     for b = 1, getn(beds) do
  1178.         local bed = beds[b];
  1179.         if (not bed.isBroken()) then
  1180.         
  1181.             local actionPoint1 = character1.getClosestFreeActionPoint(character1, bed, {"layDown1", "layDown2"});
  1182.             if (actionPoint1 and character1.canReachActionPoint(actionPoint1)) then
  1183.                 local actionPoint2Name;
  1184.                 if (actionPoint1.getName() == "layDown1") then
  1185.                     actionPoint2Name = "layDown2";
  1186.                 else
  1187.                     actionPoint2Name = "layDown1";
  1188.                 end
  1189.                 local actionPoint2 = character2.getClosestFreeActionPoint(character2, bed, {actionPoint2Name});
  1190.                 if (actionPoint2 and character2.canReachActionPoint(actionPoint2)) then
  1191.                     return bed, actionPoint1, actionPoint2;
  1192.                 else
  1193.                     print("findBedForInteraction actionPoint2 not found or cannot reach");        
  1194.                 end
  1195.             else
  1196.                 print("findBedForInteraction actionPoint1 not found or cannot reach");        
  1197.             end
  1198.         else
  1199.             print("findBedForInteraction bed.isBroken");        
  1200.         end    
  1201.     end
  1202.     
  1203.     return nil
  1204.  
  1205. end
  1206.  
  1207.  
  1208. function getInteractionBed(character1, character2)
  1209.  
  1210.     local sm1 = character1.walkSO.getStateMachine().getName();
  1211.     local s1 = character1.walkSO.getState();
  1212.     local sm2 = character2.walkSO.getStateMachine().getName();
  1213.     local s2 = character2.walkSO.getState();
  1214.     
  1215.     
  1216.     --if ((sm1 ~= "doublebedChar") or (s1 ~= "doIntimate")) then
  1217.     if (sm1 ~= "doublebedChar") then
  1218. --        print("getInteractionBed: wrong state char 1 :" .. sm1 .. "." .. s1);
  1219.         return nil 
  1220.     end;
  1221.     --if ((sm2 ~= "doublebedChar") or (s2 ~= "doIntimate")) then
  1222.     if (sm2 ~= "doublebedChar") then
  1223. --        print("getInteractionBed: wrong state char 2 :" .. sm2 .. "." .. s2);
  1224.         return nil 
  1225.     end;
  1226.     
  1227.     local bed1 = character1.getObjectWithActivity("lie");
  1228.     local bed2 = character2.getObjectWithActivity("lie");
  1229.     
  1230.     if (not bed1) then 
  1231. --        print("getInteractionBed: no bed1"); 
  1232.         return nil; 
  1233.     end;
  1234.     if (not bed2) then 
  1235. --        print("getInteractionBed: no bed2"); 
  1236.         return nil; 
  1237.     end;
  1238.     
  1239.     if (bed1 ~= bed2) then 
  1240. --        print("getInteractionBed: diferrent beds"); 
  1241.         return nil; 
  1242.     end;
  1243.     
  1244.     return bed1;
  1245.         
  1246.         
  1247. end
  1248.  
  1249. function getIntimateBed(character1, character2)
  1250.     local interactionBed = getInteractionBed(character1, character2);
  1251.     if (not interactionBed) then return nil end;
  1252.     
  1253.     local s1 = character1.walkSO.getState();
  1254.     local s2 = character2.walkSO.getState();
  1255.     
  1256.     if (s1 ~= "doIntimate") then
  1257.         print("getInteractionBed: wrong state char 1 :" .. s1);
  1258.         return nil 
  1259.     end;
  1260.     
  1261.     if (s2 ~= "doIntimate") then
  1262.         print("getInteractionBed: wrong state char 2 :" .. s2);
  1263.         return nil 
  1264.     end;
  1265.     
  1266.     return interactionBed;    
  1267. end
  1268.  
  1269.  
  1270. function getOtherUsers(character, object, activity)
  1271.  
  1272.     local result = {};
  1273.     local users = object.getCharactersWithActivity(activity);
  1274.     for u = 1, getn(users) do
  1275.         local user = users[u];
  1276.         if (user ~= character) then
  1277.             tinsert(result, user);
  1278.         end
  1279.     end
  1280.     return result;
  1281.  
  1282. end
  1283.  
  1284. function getOtherUser(character, object, activity)
  1285.     local otherUsers = getOtherUsers(character, object, activity);
  1286.     return otherUsers[1];
  1287. end
  1288.  
  1289.  
  1290. function getCharactersWithActivities(object, activities)
  1291.  
  1292.     local result = {};
  1293.     for a = 1, getn(activities) do
  1294.     local activity = activities[a];
  1295.         local users = object.getCharactersWithActivity(activity);
  1296.         for u = 1, getn(users) do
  1297.             local user = users[u];
  1298.             tinsert(result, user);
  1299.         end
  1300.     end
  1301.     return result;
  1302.  
  1303. end
  1304.  
  1305.  
  1306.  
  1307. function isUser(character, object, activities)
  1308.  
  1309.     for a = 1, getn(activities) do
  1310.     local activity = activities[a];
  1311.         local users = object.getCharactersWithActivity(activity);
  1312.         for u = 1, getn(users) do
  1313.             local user = users[u];
  1314.             if (user == character) then
  1315.                 return true;
  1316.             end
  1317.         end
  1318.     end    
  1319.     return nil;
  1320.  
  1321. end
  1322.  
  1323.  
  1324. function changeOutfit(character, outfit)
  1325.     if (not hasOutfit(character, outfit)) then
  1326.         character.changeOutfit(outfit);
  1327.     else
  1328.         print("already had that outfit");
  1329.     end
  1330. end
  1331.  
  1332.  
  1333. function hasOutfit(character, outfit)
  1334.     local current = character.getOutfit();
  1335.     return (enumCompare(outfit, current));
  1336. end
  1337.  
  1338. function getChangeOutfitAnim(character)
  1339.     if (hasOutfit(character, ARCHTYPE) or hasOutfit(character, STANDARD)) then 
  1340.         print("getChangeOutfitAnim ausziehen2");
  1341.         return "ausziehen2"; 
  1342.     else
  1343.         print("getChangeOutfitAnim ausziehen1");
  1344.         return "ausziehen1"; 
  1345.     end;
  1346. end
  1347.  
  1348.  
  1349. function replaceActivities(object, oldActivities, newActivity)
  1350.  
  1351.     local allUsers = {};
  1352.  
  1353.     for a = 1, getn(oldActivities) do
  1354.     local oldActivity = oldActivities[a];
  1355.         local users = object.getCharactersWithActivity(oldActivity);
  1356.         for u = 1, getn(users) do
  1357.             local user = users[u];
  1358.             user.stopActivity(oldActivity, object);
  1359.             tinsert(allUsers, user);
  1360.         end
  1361.     end
  1362.  
  1363.     if (not newActivity) then return end;
  1364.  
  1365.     for u = 1, getn(allUsers) do
  1366.         local user = allUsers[u];
  1367.         user.startActivity(newActivity, object);
  1368.     end
  1369.  
  1370. end
  1371.  
  1372.  
  1373.  
  1374.  
  1375. function getTableVersion(object)
  1376.  
  1377.     if (not object) then return nil; end;
  1378.  
  1379.     local name = object.getResourceName();
  1380.     local tableName = "";
  1381.     
  1382.     if     (name == "pizzaBox") then tableName = "tabletPizza";
  1383.     elseif (name == "boardgameBox") then tableName = "boardgame";
  1384.     end;
  1385.     
  1386.     if (tableName == "") then
  1387.         return object;
  1388.     else
  1389.         local tableVer = getParent().loadGameObject("StandardGO", tableName);
  1390.         return tableVer;
  1391.     end
  1392.  
  1393. end
  1394.  
  1395. function getDirtyDishVersion(object)
  1396.  
  1397.     local leftoverName = "plate";
  1398.     
  1399.     if (not object) then
  1400.         print("getDirtyDishVersion(nil) returning plate");
  1401.     else
  1402.         local name = object.getResourceName();
  1403.         
  1404.         if     (name == "tabletPizza") then leftoverName = "dirtyDishPizza";
  1405.         elseif (name == "tabletBreakfast") then leftoverName = "dirtyDishBreakfast";
  1406.         elseif (name == "tabletCooked") then leftoverName = "dirtyDishCooked";
  1407.         elseif (name == "tabletDinner") then leftoverName = "dirtyDishDinner";
  1408.         end;    
  1409.     end;
  1410.     
  1411.     local dirtyDish = getParent().loadGameObject("StandardGO", leftoverName);
  1412.     if (not dirtyDish) then
  1413.         print("getDirtyDishVersion(" .. name .. ") = " .. leftoverName .. " NOT FOUND");
  1414.     end;
  1415.     
  1416.     return dirtyDish;
  1417.  
  1418. end
  1419.  
  1420.  
  1421.  
  1422. -- called by an objects msg handler to instantly abort an impossible action. 
  1423. -- character must be in the walk-SM
  1424. function instantAbort(character, emoticon, emoMsg, sender)
  1425.  
  1426.     print("instantAbort by " .. character.getCharacterName());
  1427.     
  1428.     -- there could be a walk in the queue when walkToActionPoint 
  1429.     -- was called to find out that there is no path. clear it:
  1430.     character.walkSO.clearQueue();
  1431.     
  1432.  
  1433.     local stateMachine = character.walkSO.getStateMachine();
  1434.     local stateMachineName = stateMachine.getName();
  1435.     if (stateMachineName ~= "walk") then
  1436.         print("instantAbort(".. character.getCharacterName() ..") is in state machine " .. stateMachineName);
  1437.         -- remove the aborted queue entry manualy, because we cannot call nextAction()
  1438.         character.popQueueEntry();
  1439.     else
  1440.         character.walkSO.nextAction();
  1441.     end
  1442.     
  1443.     if (not character.getLastMsgAI()) then
  1444.     
  1445.         print("instantAbort user action");
  1446.     
  1447.         if (emoticon) then character.setEmoticon(emoticon, EMOTICON_DELAY); end;
  1448.         
  1449.         if (emoMsg) then 
  1450.             if (sender) then
  1451.                 sender.sendDelayedMsg(emoMsg, character.walkSO, 500); 
  1452.             else
  1453.                 sendDelayedMsg(emoMsg, character.walkSO, 500); 
  1454.             end;
  1455.         end;
  1456.     else
  1457.         print("instantAbort AI action");
  1458.     end    
  1459.     
  1460.     
  1461. end
  1462.  
  1463. -- called by an objects msg handler to instantly abort an impossible action. 
  1464. -- character must be in the walk-SM
  1465. function instantAbortIfNotIdle(character, charcterToCheck)
  1466.     if (not isIdle(charcterToCheck) or charcterToCheck.isSwimming()) then
  1467.         instantAbort(character, EMOTICON_CANNOT, "emoThink");
  1468.         return true;
  1469.     else
  1470.         return false;
  1471.     end;    
  1472. end
  1473.  
  1474. -- called by an objects msg handler to instantly abort an impossible action. 
  1475. -- character must be in the walk-SM
  1476. function instantAbortIfUnhappy(character, activityName, object)
  1477.  
  1478.     
  1479.     local alwaysFail = (CharacterAI.checkFailing(CharacterAI.ALWAYS_FAIL));
  1480.     local neverFail = (CharacterAI.checkFailing(CharacterAI.NEVER_FAIL));
  1481.     
  1482.     local activity = character.createActivity(activityName, object);
  1483.     local minSatisfaction = activity.getRequiredSatisfaction();
  1484.     local satisfaction = character.calculateSatisfaction();
  1485.     print("instantAbortIfUnhappy minSatisfaction " .. minSatisfaction .. " satisfaction:" .. satisfaction);
  1486.  
  1487.     if ((satisfaction < minSatisfaction or alwaysFail) and (not neverFail)) then
  1488.         instantAbort(character, EMOTICON_SAD, "emoRefuseChar", object);
  1489.         return true;
  1490.     else
  1491.         return false;
  1492.     end;    
  1493. end
  1494.  
  1495.  
  1496.  
  1497. -- this: game object
  1498. function sendMsgAllUsers(msg, activities, data)
  1499.  
  1500.     local users = getCharactersWithActivities(this, activities);
  1501.     for u = 1, getn(users) do
  1502.         local user = users[u];
  1503.         if (data) then
  1504.             sendMsg(msg, user.walkSO, data);
  1505.         else
  1506.             sendMsg(msg, user.walkSO);
  1507.         end
  1508.     end
  1509. end
  1510.  
  1511.  
  1512. -- this: tv or pc object in a active state
  1513. function startAnim(frames, frameDurration)
  1514.  
  1515.     if (not frameDurration) then frameDurration = TV_ANIM_FRAME_DURRATION; end;
  1516.  
  1517.     for f = 1, getn(frames) do
  1518.         local frame = frames[f];
  1519.         --print(frame);
  1520.         sendDelayedMsgThis("showPic", (f-1) * frameDurration, frame);
  1521.     end
  1522.     sendDelayedMsgThis("startAnim", getn(frames) * frameDurration);
  1523.  
  1524. end
  1525.  
  1526. function preloadTextures(object, texures)
  1527.     for t = 1, getn(texures) do
  1528.         object.preloadTexture(texures[t]);
  1529.     end
  1530. end
  1531.  
  1532.  
  1533.  
  1534. -- this: walkSO
  1535. function createDirt(dirtType, size, probability)
  1536.  
  1537.     if (not probability) then probability = 1.0; end; -- default value
  1538.     
  1539.     local character = getParent(); 
  1540.     
  1541.     local messy = character.getCharacterCondition(CHAR_MESSY);
  1542.     messy = 0.1 * messy; -- convert to 0.0 .. 1.0
  1543.     
  1544.     --print("prob " .. probability * messy)
  1545.     probability = probability * messy;
  1546.     if (random() > probability) then 
  1547.         --print("createDirt probability: " .. probability .. " messy: " .. messy); 
  1548.         return
  1549.     end;
  1550.     
  1551.     -- dont make dirt on some floor types
  1552.     local floorGO = getParent().getFloorUnderCharacter();
  1553.     if (floorGO) then
  1554.         local foorType = floorGO.getFloorType();
  1555.         if (tfind(NO_DIRT_FLOOR_TYPES, foorType)) then
  1556.             --print("createDirt foorType " .. foorType); 
  1557.             return
  1558.         end;
  1559.     end;
  1560.     
  1561.     -- don't make dirt outside
  1562.     local roomNumber = character.getRoomNumber();
  1563.     local room = character.getGameObjectServer().getApartment().getRoom(roomNumber);
  1564.     if (not room.isIndoor()) then 
  1565.         --print("createDirt outside"); 
  1566.         return 
  1567.     end;
  1568.     
  1569.     
  1570.     -- dont make dirt if cleaning
  1571.     local holds, hand = holdsObject(character, "hoover");
  1572.     if (holds) then return end;
  1573.     
  1574.     -- dont make dirt if someonelse cleaning
  1575.     local others = getCharactersHoldingObject(character, "hoover")
  1576.     if (getn(others) > 0) then return end;
  1577.  
  1578.     --print("createDirt by " ..  character.getCharacterName());
  1579.     character.createDirt(size, dirtType);
  1580.     
  1581. end
  1582.  
  1583. function getCharactersHoldingObject(character, objectType)
  1584.  
  1585.     local result = {};
  1586.     local others = character.getOtherCharacters();
  1587.     for c = 1, getn(others) do
  1588.         if (holdsObject(others[c], objectType)) then
  1589.             tinsert(result, others[c]); 
  1590.         end;
  1591.     end
  1592.     return result;
  1593.  
  1594. end
  1595.  
  1596. -- this: walkSO
  1597. function createTrash(amount)
  1598.  
  1599.     -- dont make dirt if cleaning
  1600.     local character = getParent(); 
  1601.  
  1602.     -- remaining trash to distribute
  1603.     local remain = amount;
  1604.     
  1605.     local trashCans = character.getObjectsWithBehavior("trashCan");
  1606.     -- go trough trashCans    
  1607.     for t = 1, getn(trashCans) do
  1608.         print("    createTrash trashCan:" .. t .. "  remain:" .. remain);
  1609.         local trashCan = trashCans[t];
  1610.         remain = addTrash(trashCan, remain);
  1611.         
  1612.         if (remain < 0.01) then 
  1613.             return
  1614.         end;
  1615.     end
  1616.     
  1617.     -- TODO: place remaing trash on floor near character
  1618.     
  1619.     character.createDirt(max(TRASH_TO_DIRT*remain, 0.1), DIRT_TRASH);
  1620.  
  1621. end
  1622.  
  1623.  
  1624.  
  1625.  
  1626. function addTrash(trashCan, amount)
  1627.  
  1628.     local canType = trashCan.getType();
  1629.     local capacity = trashCan.capacity;
  1630.     
  1631.     --if (canType == "TrashCanModern") then capacity = 1.5 end;
  1632.  
  1633.  
  1634.     local fillLevel = trashCan.retrieveData("fillLevel", 0.0);
  1635.     local newFillLevel = fillLevel + (amount/capacity);
  1636.     local remain = max(0.0, newFillLevel - 1.0);
  1637.     newFillLevel = clamp(newFillLevel, 0.0, 1.0);
  1638.      
  1639.     print("addTrash cap:" .. capacity .. " old:" .. fillLevel .. "   delta:" .. amount .. "  new:" .. newFillLevel.. "  remain:" .. remain);
  1640.     
  1641.     trashCan.storeData("fillLevel", newFillLevel);
  1642.     
  1643.     local stinkRate = newFillLevel;
  1644.     
  1645.     if (stinkRate < MIN_STINK_RATE) then
  1646.         print("no emit")
  1647.         trashCan.setChildEnable("stink", false);
  1648.     else
  1649.         print("emit")
  1650.         trashCan.setChildEnable("stink", true);
  1651.         stink = trashCan.findChildGO("stink");
  1652.         stink.setEmitRate(stinkRate);
  1653.     end
  1654.     
  1655.     trashCan.setDirtiness(newFillLevel/FULL_TRASHCAN_DIRTINESS);
  1656.     
  1657.     return remain;
  1658.     
  1659. end
  1660.  
  1661. function getDish(sink)
  1662.     local dishes = getChildrenWithBehavior(sink, "dish");
  1663.     return getn(dishes);
  1664. end
  1665.  
  1666. function addDish(sink, amount)
  1667.  
  1668.     local dishes = getChildrenWithBehavior(sink, "dish");
  1669.     local numDishes = getn(dishes);
  1670.     local maxDishes = sink.maxDishes;
  1671.     
  1672.     print("addDish(" .. amount .. ") current:" .. numDishes);
  1673.     
  1674.     if (amount > 0) then
  1675.         local toAdd = min(amount, maxDishes-numDishes);
  1676.         print("addDish toAdd:" .. toAdd);
  1677.         for i = 1, toAdd do
  1678.             local dish = sink.loadGameObject("StandardGO", "plate");
  1679.             local offsetZ = sink.dishesBaseHeight + (numDishes * dish.stackingZAdd);
  1680.             sink.addObjectToActionPoint(dish, "dish", 0, 0, offsetZ);
  1681.             numDishes = numDishes + 1;
  1682.         end
  1683.                 
  1684.         return numDishes;    
  1685.             
  1686.     elseif (amount < 0) then
  1687.         local toSub = min(abs(amount), numDishes);
  1688.         print("addDish toSub:" .. toSub);
  1689.         for i = 1, toSub do
  1690.             local dish = dishes[(numDishes-i+1)];
  1691.             dish.deleteGameObject();
  1692.         end
  1693.         
  1694.         return numDishes-toSub;        
  1695.     end
  1696.     
  1697.     return numDishes;        
  1698.     
  1699. end
  1700.  
  1701.  
  1702. function activeDiff(interaction)
  1703.  
  1704.     if (interaction == "talkFlirt") then return false; end;
  1705.     if (interaction == "talkGossip") then return false; end;
  1706.     
  1707.     return true;
  1708.  
  1709. end
  1710.  
  1711. function isMonologue(interaction)
  1712.     if (interaction == "talkRelation") then return true; end;
  1713.     return false;
  1714. end
  1715.  
  1716.  
  1717.  
  1718.  
  1719. function getIconForAction(action)
  1720.  
  1721.     if (action == "talkHobby") then return EMOTICON_HOBBY end;
  1722.     if (action == "talkComfort") then return EMOTICON_COMFORT end;
  1723.     if (action == "talkCompliment") then return EMOTICON_COMPLIMENT end;
  1724.     if (action == "talkRelation") then return EMOTICON_INLOVE end;
  1725.     if (action == "talkArgue") then return EMOTICON_ARGUE end;
  1726.     if (action == "talkCasual") then return EMOTICON_SMALLTALK end;
  1727.     if (action == "talkJoke") then return EMOTICON_JOKE end;
  1728.     if (action == "talkILoveYou") then return EMOTICON_INLOVE end;
  1729.     if (action == "talkFlirt") then return EMOTICON_EROTIC end;
  1730.     if (action == "talkTease") then return EMOTICON_TEASE end;
  1731.     if (action == "talkGossip") then return EMOTICON_GOSSIP end;
  1732.     
  1733.     return EMOTICON_DUNNO;
  1734.  
  1735. end
  1736.  
  1737. function isIdle(character)
  1738.  
  1739.     local stateMachine = character.walkSO.getStateMachine();
  1740.     local stateMachineName = stateMachine.getName();
  1741.     if (stateMachineName ~= "walk") then
  1742.         print("isIdle(".. character.getCharacterName() ..") is state machine " .. stateMachineName);
  1743.         return false;        
  1744.     end
  1745.  
  1746.     local activityQueueCount = character.getActivityQueueCount();
  1747.     if (activityQueueCount > 0) then
  1748.         print("isIdle(".. character.getCharacterName() ..") has " .. activityQueueCount .. " action queued");
  1749.         return false;
  1750.     end
  1751.     
  1752.     return true;
  1753.  
  1754. end
  1755.  
  1756. -- sets the top queue entry to the given text. if
  1757. function setTopQueueEntry(character, buttonText, clearCancel)
  1758.  
  1759.     local activityQueueCount = character.getActivityQueueCount();
  1760.     print("setTopQueueEntry " .. activityQueueCount);
  1761.     
  1762.     if (activityQueueCount == 0) then
  1763.         character.pushQueueEntry(buttonText);
  1764.     else
  1765.         local entry = character.replaceQueueEntry(0, buttonText, not clearCancel);
  1766. --        if (clearCancel) then
  1767. --            entry.clearCancel();
  1768. --            character.clearCancel();
  1769. --            character.updateActivityQueue();
  1770. --        end
  1771.     end
  1772.  
  1773. end
  1774.  
  1775. function queueFollowCommand(character, buttonText, command, object, data)
  1776.  
  1777.     if (not character) then
  1778.         print("queueFollowComand no character");
  1779.         return
  1780.     end
  1781.  
  1782.     if (not object) then
  1783.         print("queueFollowComand no object");
  1784.         return
  1785.     end
  1786.  
  1787.     local activityQueueCount = character.getActivityQueueCount();
  1788.     print("queueFollowComand " .. activityQueueCount);
  1789.     
  1790.     if (activityQueueCount == 1) then
  1791.         character.queueCommand(buttonText, command, object, data);
  1792.     end
  1793.  
  1794. end
  1795.  
  1796.  
  1797.  
  1798. function isBarefoot(character)
  1799.     local current = character.getOutfit();
  1800.     return (enumCompare(TOWEL, current) or 
  1801.         enumCompare(SWIMMING, current) or
  1802.         enumCompare(UNDERWEAR, current) or
  1803.         enumCompare(NOTHING, current));
  1804.  
  1805. end
  1806.  
  1807.  
  1808. -- this: walkWSO
  1809. function makeStepSound(foorType)
  1810.  
  1811.  
  1812.     if (not foorType) then 
  1813.         local floorGO = getParent().getFloorUnderCharacter();
  1814.         if (floorGO) then
  1815.             foorType = floorGO.getFloorType();
  1816.             --print("makeStepSound type under character " .. foorType)
  1817.         else
  1818.             foorType = "";
  1819.             --print("makeStepSound: no floor under character ")
  1820.         end
  1821.     end; 
  1822.     
  1823.     
  1824.     if isBarefoot(getParent()) then
  1825.         foorType = "Barefoot";
  1826.     end;
  1827.     
  1828.     if (not tfind(STEP_SOUNDS, foorType)) then
  1829.         foorType = "";
  1830.     end;
  1831.  
  1832.     
  1833.     local stepSound = "step" .. foorType;
  1834.     stepSound = stepSound .. random(1,2);
  1835.     
  1836.     --print("makeStepSound " .. stepSound);
  1837.     
  1838.     getParent().playSound(stepSound);
  1839.     
  1840. end
  1841.  
  1842. -- this: walkWSO
  1843. function makeChairSound(chair, sound)
  1844.  
  1845.     -- defaults
  1846.     local chairType = chair.chairType;
  1847.     if (not chairType) then chairType = "Wood"; end;
  1848.     if (not sound) then sound = "Down"; end;
  1849.     
  1850.     
  1851.     local character = getParent();
  1852.     local name = "chair" .. sound .. chairType;
  1853.     
  1854.     print("makeChairSound: " .. name);
  1855.     
  1856.     chair.playSound(name);
  1857.  
  1858. end
  1859.  
  1860.  
  1861. -- this: walkWSO
  1862. function groan(n)
  1863.     --if (getParent().isMale() == true) then
  1864.     if (false) then
  1865.         return
  1866.     else
  1867.         if (not n) then n = random(1,9); end;
  1868.         local sound = "groan" .. n;
  1869.         sound = genderizeReal(getParent(), sound);
  1870.         print("sound " .. sound .. "  by " .. getParent().getCharacterName());
  1871.         getParent().playSound(sound);
  1872.     end
  1873. end
  1874.  
  1875.  
  1876. function swapDirtTextures(object)
  1877.  
  1878. --    local textures = {"kloOldschool", "kloModern"}; -- TODO: get from dynamic attribs
  1879.  
  1880.     if (not object.dirtableTextures) or (not object.dirtSteps) then return end;
  1881.  
  1882.     local textures = object.dirtableTextures;
  1883.     local step = 1 / object.dirtSteps;
  1884.     
  1885.  
  1886.         
  1887.     
  1888.     local dirt = object.getDirtiness();
  1889.     local suffix = "";
  1890.     
  1891.     local level = floor(dirt / step);
  1892.     level = clamp(level, 0, object.dirtSteps - 1);
  1893.     if (level > 0) then suffix = "_d" .. level; end;
  1894.     
  1895.     print("dirtStep:" .. step .. " level:" .. level .. " suffix:" .. suffix);
  1896.     
  1897.     
  1898. --    if    (dirt > 0.75) then suffix = "_d3";
  1899. --    elseif    (dirt > 0.50) then suffix = "_d2";
  1900. --    elseif    (dirt > 0.25) then suffix = "_d1"; 
  1901. --    end;
  1902.     
  1903.     
  1904.     for i = 1, getn(textures) do
  1905.         local texture = textures[i];
  1906.         local newTexture = texture .. suffix;
  1907.         print("swapDirtTextures: " .. texture .. " -> " .. newTexture);
  1908.         object.replaceTexture(texture, newTexture);
  1909.     end
  1910.     
  1911. end
  1912.  
  1913.  
  1914.  
  1915. function changeDirtiness(object, amount)
  1916.     
  1917.     local oldDirt = object.getDirtiness();
  1918.     local newDirt = oldDirt + amount;
  1919.     newDirt = clamp(newDirt, 0.0, 1.0);
  1920.     
  1921.     print("change dirt of " .. object.getType() .. " from " .. oldDirt .. " to " .. newDirt);
  1922.         
  1923.     object.setDirtiness(newDirt);
  1924.     
  1925.     swapDirtTextures(object);
  1926. end
  1927.  
  1928. -- this: walkWSO
  1929. function clean(object, amount)
  1930.  
  1931.     local character = getParent();
  1932.     
  1933.     local clean = character.createActivity("clean", object);
  1934.     local effect = clean.getEffectivity();
  1935.     
  1936.     amount = -(amount * effect);
  1937.     
  1938.     changeDirtiness(object, amount);
  1939. end
  1940.  
  1941. -- this: walkWSO
  1942. function dirtify(object, amount)
  1943.  
  1944.     local character = getParent();
  1945.     
  1946.     local messy = character.getCharacterCondition(CHAR_MESSY);
  1947.     messy = (0.1 * messy) - 0.5; -- scale to -1.0 .. 1.0
  1948.     amount = max(amount, 0.0);
  1949.  
  1950.     amount = amount + (amount * messy);
  1951.     
  1952.     changeDirtiness(object, amount);
  1953. end
  1954.  
  1955.  
  1956. -- returns true (the name of the action point) if this door is a bathroom door
  1957. function isBathroomDoor(doorGO)
  1958.     local actionPoints = doorGO.getActionPoints();
  1959.     for i = 1, getn(actionPoints) do
  1960.         local actionPoint = actionPoints[i];
  1961.         local room = doorGO.getRoomFromActionPoint(actionPoint);
  1962.         if (room) then
  1963.             if (room.getRoomTypeValue(BATHROOM) > 0) then
  1964.                 return actionPoint.getName();
  1965.             end
  1966.         end
  1967.     end
  1968.     
  1969.     return false;
  1970. end
  1971.  
  1972. -- this: walkSO
  1973. function checkShortcut(object, commands, states, messages)
  1974.  
  1975.     local character = getParent();
  1976.     local entry = character.peekActivityQueue();
  1977.     
  1978.     local entryCommand = entry.getCommand();
  1979.     local entryObject = entry.getGameObject();
  1980.     local entryData = entry.getData();
  1981.     
  1982.     if (not object) then
  1983.         print("checkShortcut no valid object");
  1984.         return false;
  1985.     end;
  1986.  
  1987.     if (not entryObject) then
  1988.         print("checkShortcut no valid entryObject:" .. tostring(entryObject));
  1989.         return false;
  1990.     end;
  1991.  
  1992.     if (entryObject ~= object) then
  1993.         print("checkShortcut wrong object:" .. object.getType() .. " queue:" .. entryObject.getType());
  1994.         return false;
  1995.     end
  1996.     
  1997.     local index = tfind(commands, entryCommand)
  1998.         
  1999.     if (not index) then index = tfind(commands, entryData) end;
  2000.     
  2001.     if (not index) then
  2002.         print("checkShortcut command not found!  command:" .. entryCommand .. " data:" .. entryData);
  2003.         return false
  2004.     end
  2005.     
  2006.     if (getn(commands) ~= getn(states)) then
  2007.         print("checkShortcut given: " .. getn(commands) .. " commands but " .. getn(states) .. " states");
  2008.         return false
  2009.     end
  2010.     
  2011.     print("checkShortcut -> taking shortcut to state: " .. states[index]);
  2012.     
  2013.     character.popQueueEntry();
  2014.     clearCancel();
  2015.     
  2016.     if (messages) then
  2017.         local message = messages[index];
  2018.         if (message) then
  2019.             print("checkShortcut sending msg:" .. message .. " data:" .. tostring(entryData) .. " to " .. object.getType());
  2020.             character.sendMsg(message, entryObject, tostring(entryData));
  2021.         end;
  2022.     end    
  2023.  
  2024. --    if (messages) then
  2025. --        local message = messages[index];
  2026. --        if (message) then
  2027. --            print("checkShortcut sending msg:" .. message .. " to " .. object.getType());
  2028. --            character.sendMsg(message, object);
  2029. --        end;
  2030. --    end    
  2031.     
  2032.     setState(states[index]);
  2033.     
  2034.     
  2035. --    if (messages) then
  2036. --        local message = messages[index];
  2037. --        if (message) then
  2038. --            local name, data = strsplit(message, ".");
  2039. --            if (data) then
  2040. --                print("checkShortcut sending msg:" .. name .. " data:" .. data .. " to " .. object.getType());
  2041. --                character.sendMsg(name, object, data);
  2042. --            else
  2043. --                print("checkShortcut sending msg:" .. name .. " to " .. object.getType());
  2044. --                character.sendMsg(name, object);
  2045. --            end
  2046. --        end;
  2047. --    end
  2048.     
  2049.     return true;    
  2050.  
  2051. end
  2052.  
  2053. -- this: walkSO
  2054. function checkWatchShortcut(object, commands, states, messages)
  2055.  
  2056.     local character = getParent();
  2057.     local entry = character.peekActivityQueue();
  2058.     
  2059.     local entryCommand = entry.getCommand();
  2060.     local entryObject = entry.getGameObject();
  2061.     local entryData = entry.getData();
  2062.     
  2063.     if (not object) then
  2064.         print("checkShortcut no valid object");
  2065.         return false;
  2066.     end;
  2067.  
  2068.     if (not entryObject) then
  2069.         print("checkShortcut no valid entry");
  2070.         return false;
  2071.     end;
  2072.  
  2073.     local optimalSeat = getNextWatchSit(character, entryObject, 1.0, 1.5);
  2074.     if (not optimalSeat) then
  2075.         print("checkShortcut no optimalSeat");
  2076.         return false;
  2077.     end
  2078.     
  2079.     
  2080.     if (optimalSeat ~= object) then
  2081.         print("checkShortcut wrong optimalSeat:" .. optimalSeat.getType() .. " currentSeat:" .. object.getType());
  2082.         return false;
  2083.     end
  2084.     
  2085.     local index = tfind(commands, entryCommand)
  2086.         
  2087. --    if (not index) then index = tfind(commands, entryData) end;
  2088.     
  2089.     if (not index) then
  2090.         print("checkShortcut command not found!  command:" .. entryCommand .. " data:" .. entryData);
  2091.         return false
  2092.     end
  2093.     
  2094.     if (getn(commands) ~= getn(states)) then
  2095.         print("checkShortcut given: " .. getn(commands) .. " commands but " .. getn(states) .. " states");
  2096.         return false
  2097.     end
  2098.     
  2099.     print("checkShortcut -> taking shortcut to state: " .. states[index]);
  2100.     
  2101.     character.popQueueEntry();
  2102.     clearCancel();
  2103.     
  2104.     
  2105.     if (messages) then
  2106.         local message = messages[index];
  2107.         if (message) then
  2108.             print("checkShortcut sending msg:" .. message .. " data:" .. tostring(entryData) .. " to " .. object.getType());
  2109.             character.sendMsg(message, entryObject, tostring(entryData));
  2110.         end;
  2111.     end    
  2112.     
  2113.     setState(states[index]);
  2114.     
  2115.     
  2116.     return true;    
  2117.  
  2118. end
  2119.  
  2120.  
  2121.  
  2122.  
  2123.  
  2124. function getSofaIteractionInfo(character1, character2)
  2125.  
  2126.     
  2127.     local male = 0;
  2128.     if (character1.isMale()) then male = 1; else male = 2; end;
  2129.     
  2130.     local wso1 = character1.walkSO;
  2131.     local wso2 = character2.walkSO;
  2132.     
  2133.     local actionPointName1 = wso1.retrieveData("actionPointName");
  2134.     local actionPointName2 = wso2.retrieveData("actionPointName");
  2135.     
  2136.     if ((not actionPointName1) or (not actionPointName2)) then 
  2137.         print("getSofaIteractionInfo fail actionPointName");
  2138.         return false;
  2139.     end;
  2140.     
  2141.     local sofa1 = character1.getObjectWithActivity("sit");
  2142.     local sofa2 = character1.getObjectWithActivity("sit");
  2143.     
  2144.     if ((not sofa1) or (not sofa2) or (sofa1 ~= sofa2)) then 
  2145.         print("getSofaIteractionInfo fail sofa");
  2146.         return false;
  2147.     end;
  2148.     
  2149.     local possible;
  2150.     local mirrorAnims;
  2151.     
  2152.     
  2153.     if     (actionPointName1 == "sit1" and actionPointName2 == "sit2") then
  2154.         possible = true;
  2155.         mirrorAnims = (male == 2);
  2156.     elseif (actionPointName1 == "sit2" and actionPointName2 == "sit1") then
  2157.         possible = true;
  2158.         mirrorAnims = (male == 1);
  2159.     elseif (actionPointName1 == "sit2" and actionPointName2 == "sit3") then
  2160.         possible = true;
  2161.         mirrorAnims = (male == 2);
  2162.     elseif (actionPointName1 == "sit3" and actionPointName2 == "sit2") then
  2163.         possible = true;
  2164.         mirrorAnims = (male == 1);
  2165.     else
  2166.         possible = false;
  2167.         mirrorAnims = false;
  2168.     end
  2169.         
  2170.     return possible, mirrorAnims;
  2171. end
  2172.  
  2173.  
  2174. -- this walkSO with "activePart" stored
  2175. function getInteractionWaitTime()
  2176.     if retrieveData("activePart") or retrieveData("waitLong") then
  2177.         return WAIT_INTERACTION_ACTIVE;
  2178.     else
  2179.         return WAIT_INTERACTION_PASSIVE;
  2180.     end
  2181. end
  2182.  
  2183.  
  2184. function getStoredOrSender(name, msg)
  2185.  
  2186.     if (type(name) == "table") then
  2187.         for n = 1, getn(name) do
  2188.             print(">getStoredOrSender name table element " .. name[n]);
  2189.             local stored = retrieveStateObject(name[n]);
  2190.             if (stored) then
  2191.                 print(">getStoredOrSender stored as " .. name[n]);
  2192.                 return stored;
  2193.             end
  2194.         end
  2195.     else
  2196.         local stored = retrieveStateObject(name);
  2197.         if (stored) then
  2198.             print(">getStoredOrSender stored as " .. name);
  2199.             return stored;
  2200.         end
  2201.     end
  2202.  
  2203.     print(">getStoredOrSender not stored");
  2204.     return getStateObjectFromID(msg.sender);    
  2205. end
  2206.  
  2207. function unlockAll(storeName)
  2208.  
  2209.     local character = getParent();
  2210.     local object = retrieveStateObject(storeName);
  2211.     if (object) then
  2212.         character.unlockActionPoints(object);
  2213.         character.stopAllActivities(object);
  2214.         object.stopAllSounds();
  2215.     end;
  2216.     removeStateObject(storeName);
  2217.  
  2218. end
  2219.  
  2220.  
  2221. function getEatActivityName(tablet)
  2222.  
  2223.     local activity = tablet.activity;
  2224.     if (not activity) then
  2225.         activity = "eat";
  2226.     end
  2227.     return activity;
  2228.  
  2229. end
  2230.  
  2231. function hasLightenCandles(table)
  2232.  
  2233.     local children = table.getGOChildren();
  2234.     for c = 1, getn(children) do
  2235.         local child = children[c];
  2236.         if (child.hasBehavior("candle") and child.getLightOn()) then
  2237.             return true;
  2238.         end
  2239.     end
  2240.     return false;
  2241.     
  2242. end
  2243.  
  2244.  
  2245. -- this: walkSO
  2246. -- finds character sitting at the same table in front of this character
  2247. function getTableTalkPartner(tablet)
  2248.  
  2249.     local table = retrieveStateObject("table");
  2250.     local tableActionPointName = retrieveData("tableActionPointName");
  2251.     if ((not table) or (not tableActionPointName)) then
  2252.         print("lookForPartner: no table or tableActionPointName");
  2253.         return nil;
  2254.     end
  2255.     
  2256.     local partnerChair = getOpposedChair(table, tableActionPointName);
  2257.     if (not partnerChair) then
  2258.         print("lookForPartner: no partner chair found");
  2259.         return nil;
  2260.     end
  2261.     
  2262.     local siting = partnerChair.getCharactersWithActivity("sit");
  2263.     local partner = siting[1];
  2264.     if (not partner) then
  2265.         print("lookForPartner: no partner found");
  2266.         return nil;
  2267.     end
  2268.     
  2269.     -- somebody is sitting in front of characer -> smalltalk
  2270.     print("partner found -> smalltalk");
  2271.     return partner;
  2272.     
  2273. end
  2274.  
  2275. function canLeave(character)
  2276.  
  2277.     local gameObjectServer = character.getGameObjectServer();
  2278.     
  2279.         
  2280.     local current = gameObjectServer.getOutsideWorld();
  2281.     
  2282.     local other = getOtherCharacter(character);
  2283.     if ((not other) or (not other.getAtHome())) then
  2284.         return false;
  2285.     end;
  2286.     
  2287.     
  2288.     if (enumCompare(current, CITY)) then
  2289.         print("canLeave to COUNTRY");
  2290.         
  2291.         local cheat = (readConfig("Debug", "beachHouseAlways", "false") == "true");
  2292.         local neverFail = CharacterAI.checkFailing(CharacterAI.NEVER_FAIL);
  2293.         if (cheat or neverFail) then
  2294.             return true;
  2295.         end
  2296.         
  2297.             
  2298.         -- wenn sie das Ja-Wort gegeben hat - vorsicht nicht den honeymoonquest zerschiessen!!
  2299.         if (    gameObjectServer["mission"] and 
  2300.             gameObjectServer["mission"]["questHoneymoon"] and 
  2301.             gameObjectServer["mission"]["questHoneymoon"].getState() == "done" ) then
  2302.                 
  2303.                 return true;
  2304.         
  2305. --                -- TODO: check if they have the beach house already
  2306. --                local mike = gameObjectServer.getCharacter(MIKE);
  2307. --                local elaine = gameObjectServer.getCharacter(ELAINE);
  2308. --                local minCond = min(    mike.getRelationshipCondition(ELAINE, REL_FRIENDSHIP),
  2309. --                            elaine.getRelationshipCondition(MIKE, REL_FRIENDSHIP));
  2310. --                if (minCond < 5) then
  2311. --                    return false;
  2312. --                end
  2313.                 ------------------------------------------------------
  2314.                 
  2315.                 
  2316. --                local gameDate = gameObjectServer.getGameDate();
  2317. --                local weekDay = gameDate.getWeekDay();
  2318. --                local hour = gameDate.getHours();
  2319. --                
  2320. --                if (enumCompare(weekDay, SATURDAY) or enumCompare(weekDay, SUNDAY)) then
  2321. --                    return true;
  2322. --                end
  2323. --                
  2324. --                if (enumCompare(weekDay, FRIDAY) and not character.timeForWork()) then
  2325. --                    return true;
  2326. --                end
  2327.         else
  2328.             print("questHoneymoon not done yet ");
  2329.         end
  2330.     
  2331.     else
  2332.         print("canLeave to CITY");
  2333.         return true;
  2334.     end
  2335.     
  2336.     return false;
  2337.     
  2338. end
  2339.  
  2340. function toggleOutsideWorld(gameObject)
  2341.  
  2342.     local gameObjectServer = gameObject.getGameObjectServer();
  2343.     local current = gameObjectServer.getOutsideWorld();
  2344.     if (enumCompare(current, CITY)) then
  2345.         print("toggleOutsideWorld to COUNTRY");
  2346.         gameObjectServer.setOutsideWorldDeferred(COUNTRY);
  2347.     else
  2348.         print("toggleOutsideWorld to CITY");
  2349.         gameObjectServer.setOutsideWorldDeferred(CITY);
  2350.     end
  2351. end
  2352.  
  2353. function getOtherWaitingToLeave(character, staircase)
  2354.  
  2355.     local other = getOtherCharacter(character);
  2356.     
  2357.     if (not other) or (not staircase) then return nil; end;
  2358.     
  2359.     local oStateMachine = other.walkSO.getStateMachine().getName();
  2360.     local oState = other.walkSO.getState();
  2361.     local oStaircase = other.walkSO.retrieveStateObject("staircase");
  2362.     
  2363. --    print("getOtherWaitingToLeave oStateMachine " .. oStateMachine);
  2364. --    print("getOtherWaitingToLeave oState " .. oState);
  2365. --    print("getOtherWaitingToLeave oStaircase " .. tostring(oStaircase));
  2366. --    print("getOtherWaitingToLeave tStaircase " .. tostring(staircase));
  2367. --    if (oStaircase) then 
  2368. --        print("getOtherWaitingToLeave oStaircase " .. oStaircase.getUniqueID());
  2369. --    end        
  2370. --    print("getOtherWaitingToLeave tStaircase " .. staircase.getUniqueID());
  2371.     
  2372.     if (oStateMachine == "staircaseChar") and (oState == "atOtherHouse") and (oStaircase == staircase) then
  2373.         print("getOtherWaitingToLeave found");
  2374.         return other;
  2375.     end
  2376.     
  2377.     return nil;
  2378.  
  2379. end
  2380.  
  2381.  
  2382. function getLeaveButtonText(gameObject)
  2383.  
  2384.     local gameObjectServer = gameObject.getGameObjectServer();
  2385.     local current = gameObjectServer.getOutsideWorld();
  2386.     if (enumCompare(current, CITY)) then
  2387.         return "pm_gotoCountry";
  2388.     else
  2389.         return "pm_gotoCity";
  2390.     end
  2391.     
  2392.     return "pm_goOut";    
  2393. end
  2394.  
  2395. function getComeBackButtonText(gameObject)
  2396.  
  2397.     local gameObjectServer = gameObject.getGameObjectServer();
  2398.     local current = gameObjectServer.getOutsideWorld();
  2399.     if (enumCompare(current, CITY)) then
  2400.         return "pm_fromCountry";
  2401.     else
  2402.         return "pm_fromCity";
  2403.     end
  2404.     
  2405.     return "pm_goOut";    
  2406. end
  2407.  
  2408.  
  2409. function canMarry(char1, char2)
  2410.     if char1.isMale() then
  2411.         local mike = char1;
  2412.         local elaine = char2;
  2413.  
  2414.         local friendship = min(mike.getRelationshipCondition(ELAINE, REL_FRIENDSHIP),
  2415.             elaine.getRelationshipCondition(MIKE, REL_FRIENDSHIP));
  2416.         local romantic = min(mike.getRelationshipCondition(ELAINE, REL_ROMANTIC),
  2417.             elaine.getRelationshipCondition(MIKE, REL_ROMANTIC));
  2418.         local erotic = min(mike.getRelationshipCondition(ELAINE, REL_EROTIC),
  2419.             elaine.getRelationshipCondition(MIKE, REL_EROTIC));
  2420.         local questHoneymoon = char1.getGameObjectServer()["mission"]["questHoneymoon"];
  2421.  
  2422.         if ( 
  2423.             not (questHoneymoon and questHoneymoon.getState() == "done")
  2424.             and
  2425.             (            
  2426.                 ( -- eines davon 10 und die anderen mindestens 5 sind und der honeymoon-quest schon im state "marryme" ist
  2427.                     max(max(friendship, romantic), erotic) >= 10
  2428.                     and    
  2429.                     min(min(friendship, romantic), erotic) >= 5
  2430.                     and
  2431.                     questHoneymoon and questHoneymoon.getState() == "waitForMarriage"
  2432.                 )
  2433.                 or
  2434.                 ( -- falls questHoneymoon hΣngt: alle drei Bewertungen 10 sind - man also praktisch fertig ist
  2435.                     min(min(friendship, romantic), erotic) >= 10
  2436.                 )
  2437.             )
  2438.         )
  2439.         then
  2440.             -- here condition for marriage
  2441.             return true;
  2442.         end
  2443.     else
  2444.         return false;
  2445.     end
  2446. end
  2447.  
  2448. -- this: walkSO in intraction
  2449. function storeActivityPossible(activity)
  2450.  
  2451.     local thisChar = getParent();
  2452.     local partner = retrieveStateObject("partner");
  2453.  
  2454.     if not partner then
  2455.         print("storeActivityPossible no partner");
  2456.         return 
  2457.     end
  2458.     
  2459.     local partnerChar = partner.getParent();
  2460.     
  2461.     
  2462.     local activePart = retrieveData("activePart");
  2463.     
  2464.     local active = cond(activePart, thisChar, partnerChar);
  2465.     local passive = cond(activePart, partnerChar, thisChar);
  2466.     
  2467.     local result = activityPossible(active, activity, passive);
  2468.     storeData("activityPossible", result);
  2469.     
  2470.     print("storeActivityPossible stored: " .. tostring(result));
  2471.     print(">>active : " .. active.getCharacterName());
  2472.     print(">>passive : " .. passive.getCharacterName());
  2473.     
  2474. end
  2475.  
  2476. -- this: questSO
  2477. function talkingCancelled(charID, topic)
  2478.  
  2479.     local gameObjectServer = getParent().getParent();
  2480.     local character = gameObjectServer.getCharacter(charID);
  2481.     if character then
  2482.         local walkSO = character.walkSO;
  2483.         if walkSO then
  2484.             print("talkingCancelled topic: " .. topic .. " to" .. character.getCharacterName());
  2485.             sendMsg("talkingCancelled", walkSO, topic);
  2486.         end
  2487.     end
  2488.     
  2489. end
  2490.  
  2491.